package Pointers;

import interfaces.PointerOffsetGenerator;

import java.util.ArrayList;

import Script.Offset;

/**
 * Generates a set of pointers by specifying start and
 * stop offset, as well as pointer size.
 * 
 * @author Aeris130
 *
 */
public class OffsetRangeGenerator implements PointerOffsetGenerator {
	private Offset 	start;
	private Offset 	stop;
	private int 	byteSize;
	private int 	byteSpace;
	
	/**
	 * @param start Starting offset to begin generating from. Inclusive.
	 * @param stop Ending offset. Exclusive.
	 * @param byteSize Size of each pointer in bytes.
	 * @param byteSpace Number of bytes between each pointer. 0 if they're
	 * 					all present in a coherent pointer table.
	 */
	public OffsetRangeGenerator(Offset start, Offset stop, 
								int byteSize, int byteSpace) {
		
		this.start = start;
		this.stop = new Offset(stop.getValue() - 1);
		this.byteSize = byteSize;
		this.byteSpace = byteSpace;
		
	}
	
	
	public ArrayList<Offset> getOffsets() {
		ArrayList<Offset> offsets = new ArrayList<Offset>();
		long offsetRange;
		long currentOffset = 0;
		
		/* Do not retrieve data if parameters are invalid. */
		if (!isValid()) {
			return null;
		}
		
		/*
		 * Generate offsets until the entire offset range has
		 * been covered.
		 */
		offsetRange = stop.getValue() - start.getValue() + 1;
		
		while (offsetRange > 0) {
			offsets.add(new Offset(start.getValue() + currentOffset));
			
			offsetRange -= (byteSize + byteSpace);
			currentOffset += (byteSize + byteSpace);
		}
		
		return offsets;
	}
	
	/**
	 * Checks if the submitted parameters are valid or not.
	 * 
	 * @return True if parameters are valid, otherwise false.
	 */
	private boolean isValid() {
		float offsetRange;
		
		/* Basic argument validation. */
		if (start.getValue() > stop.getValue()) {
			return false;
			
		} else if (byteSize < 1) {
			return false;
			
		} else if (byteSpace < 0 
					|| byteSpace > (stop.getValue() - start.getValue())) {
			return false;
		}
		
		/* 
		 * Check if the offsets can hold an exact number of pointers,
		 * given the pointer size and number of bytes between each pointer.
		 * 
		 * Formula: # of pointer = 
		 * (offsetRange - byteSize) / (byteSize + byteSpace)
		 * 		+ 1
		 * 
		 * This number can not be a floating point. The +1 is discarded in
		 * the calculation, since it does not affect the outcome in a way
		 * that modifies the validity.
		 */
		
		offsetRange = stop.getValue() - start.getValue() + 1;
		
		if ((offsetRange - byteSize) % (byteSize + byteSpace) != 0) {
			return false;
		}
		
		/* Indata validates. */
		return true;
	}
}
